﻿// -------------------------------------------------------------------------
//    @FileName         :    CustomPacketParse.cpp
//    @Author           :    Gao.Yi
//    @Date             :   2022-09-18
//    @Email			:    445267987@qq.com
//    @Module           :    CustomPacketParse
//
// -------------------------------------------------------------------------
#include "CustomPacketParse.h"

#include <proto_client2access.pb.h>
#include "NFComm/NFPluginModule/NFNetDefine.h"
#include "NFComm/NFPluginModule/NFLogMgr.h"

#if NF_PLATFORM == NF_PLATFORM_WIN
#else
#include <netinet/in.h>
#endif

CustomPacketParse::CustomPacketParse()
{
}

bool CustomPacketParse::IsPacketComplete(const char* szPackBuf, int iPackLen)
{
    if (iPackLen < MSG_HEAD_LEN)
    {
        return false;
    }

    uint32_t* lens32 = (uint32_t*)szPackBuf;
    int32_t iPacketLen = ntohl(lens32[0]);

    if (iPackLen < iPacketLen)
    {
        return false;
    }

    return true;
}

int CustomPacketParse::UnpackC2AHead(const char* szPackBuf, int iPackLen, proto_client2access::C2AMsgHead& oMsgHead, int& iHeadLen, int& iDataLen)
{
    uint16_t* lens = (uint16_t*)szPackBuf;
    uint32_t* lens32 = (uint32_t*)szPackBuf;
    iDataLen = ntohl(lens32[0]);
    iHeadLen = ntohs(lens[2]);
    if (unlikely(!oMsgHead.ParseFromArray( szPackBuf + MSG_HEAD_LEN, iHeadLen )))
    {
        NFLogError(NF_LOG_DEFAULT, 0, " parse proto_client2access::C2AMsgHead error!");
        return -1;
    }

    return 0;
}

int CustomPacketParse::DeCodeImpl(const char* strData, uint32_t unLen, char*& outData, uint32_t& outLen, uint32_t& allLen, NFDataPackage& recvPackage)
{
    if (strData == nullptr || unLen == 0)
        return 1;

    if (unLen < MSG_HEAD_LEN)
    {
        return 1;
    }

    if (!IsPacketComplete(strData, unLen))
    {
        return 1;
    }

    int iHeadLen = 0;
    int iPackLen = 0;
    proto_client2access::C2AMsgHead oMsgHead;
    int iRet = UnpackC2AHead(strData, unLen, oMsgHead, iHeadLen, iPackLen);
    if (iRet != 0)
    {
        NFLogError(NF_LOG_DEFAULT, 0, "UnpackC2AHead parse data failed, unLen:{}", unLen);
        return -1;
    }

    const ::google::protobuf::Descriptor* descriptor = oMsgHead.GetDescriptor();
    if (descriptor == NULL)
    {
        NFLogError(NF_LOG_DEFAULT, 0, "oMsgHead.GetDescriptor() failed");
        return -1;
    }
    const ::google::protobuf::FieldDescriptor* field_descriptor = descriptor->FindFieldByName("magic");
    if (field_descriptor == NULL)
    {
        NFLogError(NF_LOG_DEFAULT, 0, "descriptor->FindFieldByName(\"magic\") failed");
        return -1;
    }

    if (field_descriptor->default_value_int32() != oMsgHead.magic())
    {
        NFLogError(NF_LOG_DEFAULT, 0, "magic error, ield_descriptor->default_value_int32():{} oMsgHead.magic():{}", field_descriptor->default_value_int32(), oMsgHead.magic());
        return -1;
    }

    outData = const_cast<char*>(strData + MSG_HEAD_LEN + iHeadLen);
    outLen = iPackLen - MSG_HEAD_LEN - iHeadLen;

    if (iPackLen >= MAX_RECV_BUFFER_SIZE || iPackLen < MSG_HEAD_LEN || outLen != oMsgHead.transferdata_len())
    {
        NFLogError(NF_LOG_DEFAULT, 0, "net server parse data failed, iPackLen:{} == 6 + iHeadLen:{} transferdata_len:{} cmd:{} msg_seq:{}", iPackLen, iHeadLen, oMsgHead.transferdata_len(), oMsgHead.cmd(), oMsgHead.msg_seq());
        return -1;
    }

    if (oMsgHead.cmd() == proto_client2access::E_C2A_TRANSFERDATA)
    {
        if (outLen < sizeof(CSC2SPkgHead))
        {
            NFLogError(NF_LOG_DEFAULT, 0, "net server parse data failed, outLen:{} < sizeof(CSC2SPkgHead)", outLen, sizeof(CSC2SPkgHead));
            return -1;
        }
    }

    recvPackage.mModuleId = NF_MODULE_CLIENT;
    recvPackage.nMsgId = oMsgHead.cmd();
    recvPackage.nParam1 = 0;
    recvPackage.nParam2 = 0;
    recvPackage.bCompress = false;
    recvPackage.nMsgSeq = oMsgHead.msg_seq();
    allLen = iPackLen;

    return 0;
}

int CustomPacketParse::EnCodeImpl(const NFDataPackage& recvPackage, const char* strData, uint32_t unLen, NFBuffer& buffer, uint64_t nSendBusLinkId)
{
    ::proto_client2access::C2AMsgHead oMsgHead;
    const ::google::protobuf::Descriptor* descriptor = oMsgHead.GetDescriptor();
    const ::google::protobuf::FieldDescriptor* field_descriptor = descriptor->FindFieldByName("magic");

    oMsgHead.set_msg_seq(recvPackage.nMsgSeq);
    oMsgHead.set_magic(field_descriptor->default_value_int32());
    oMsgHead.set_transferdata_len(unLen);
    oMsgHead.set_cmd((proto_client2access::Proto_C2ACmd)recvPackage.nMsgId);

    ::std::string strSerialHead;
    oMsgHead.SerializePartialToString(&strSerialHead);

    int32_t iTotalLen = MSG_HEAD_LEN + strSerialHead.size() + unLen;
    if ((int32_t)buffer.WritableSize() < iTotalLen)
    {
        NFLogError(NF_LOG_DEFAULT, 0, "net server send data failed, buffer size:{}, iTotalLen:{} head:6 C2AMsgHead:{} unLen:{}", buffer.WritableSize(), iTotalLen, strSerialHead.size(), unLen);
        return 0;
    }

    char* pPackBuf = buffer.WriteAddr();
    uint16_t* iLens = (uint16_t*)pPackBuf;
    uint32_t* lens32 = (uint32_t*)pPackBuf;
    lens32[0] = htonl(iTotalLen);
    iLens[2] = htons((uint16_t)strSerialHead.size());
    buffer.Produce(MSG_HEAD_LEN);
    buffer.PushData(strSerialHead.data(), strSerialHead.size());
    buffer.PushData(strData, unLen);

    //NFLogTrace(NF_LOG_DEFAULT, 0, "send package, iTotalLen:{} iHeadLen:{} unLen:{}", iTotalLen, strSerialHead.size(), unLen);

    return iTotalLen;
}

// 使用 lzf 算法 压缩、解压
int CustomPacketParse::CompressImpl(const char* inBuffer, int inLen, void* outBuffer, unsigned int outSize)
{
    return 0;
}

int CustomPacketParse::DecompressImpl(const char* inBuffer, int inLen, void* outBuffer, int outSize)
{
    return 0;
}
